package servlet;

import java.io.File;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import servlet.events.EventHandler;
import servlet.events.EventHandlerFactory;
import util.Debug;

/**
 * Servlet implementation class MyFirstServlet
 */
public class ServletController extends HttpServlet {
	private static final long serialVersionUID = 1L;
    private Map<String, EventHandler> handlers = new HashMap<String, EventHandler>();
	private static Map<String, String> parameterMap = new HashMap<String, String>();
	
    /**
     * @see HttpServlet#HttpServlet()
     */
    public ServletController() {
        super();
    }

    @Override
    public void init() throws ServletException {
    	//super.init();
    	
    	//load Event handlers
    	ResourceBundle bundle = ResourceBundle.getBundle("Events");
    	
    	Enumeration<String> e = bundle.getKeys();
    	
    	while(e.hasMoreElements()) {
    		String key = e.nextElement();
    		String value = bundle.getString(key);
    		
    		try {
				EventHandler handler = (EventHandler) Class.forName(value).newInstance();
				handlers.put(key, handler);
				Debug.log(this, "init", "event:" + key + ", handler: " + handler.getClass().getName());
			} catch (Exception ex) {
				Debug.log(this, "init", "event:" + key + ", NO HANDLER FOUND: " + value);
			}
    	}
    }
	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	
		//load Parameters
    	loadParamaterMap(request);
    	
		response.setContentType("text/html");
			
		//String event = request.getParameter(Constants.EVENT_NAME);
		String event = getParameter(Constants.EVENT_NAME);
		if (event == null || !handlers.containsKey(event)) {
			event = Constants.UNKNOWN_EVENT;
		}
		
		EventHandlerFactory handlerFactory = new EventHandlerFactory(handlers);
		EventHandler handler = handlerFactory.getHandler(event);
		
		handler.execute(request, response);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}

	//used intentionally to get parameter value from a 'multipart/form-data' enctyped form (eg, upload file...)
	public static String getParameter(String name) {
		Debug.log(new ServletController(), "getParameter", name + " = " + parameterMap.get(name));
		return (String) parameterMap.get(name);
	}
	
	private void loadParamaterMap(HttpServletRequest request) {
		boolean isMultipart = ServletFileUpload.isMultipartContent(request);
		
		/**not Multipart**/
		if (!isMultipart) {
			@SuppressWarnings("unchecked")
			Enumeration<String> paraNames = request.getParameterNames();
			while (paraNames.hasMoreElements()) {
				String paraName = paraNames.nextElement();
				parameterMap.put(paraName, request.getParameter(paraName));
				Debug.log(this, "loadParamaterMap", paraName + "/" + request.getParameter(paraName));
			}
			return;
		}
		
		loadParameterWithMultipart(request);
	}
	
	@SuppressWarnings("unchecked")
	private void loadParameterWithMultipart(HttpServletRequest request) {
		Debug.log(this, "loadParameterWithMultipart", "multipart/form-data");
		/**Multipart/form-data**/		
		Enumeration<String> paraNames = request.getParameterNames();		
		while (paraNames.hasMoreElements()) {
			String paraName = paraNames.nextElement();
			parameterMap.put(paraName, request.getParameter(paraName));
		}
		try {
			ServletFileUpload uploader = new ServletFileUpload(new DiskFileItemFactory());
			
			List<FileItem> items = uploader.parseRequest(request);
			
			Iterator<FileItem> itr = items.iterator();
			while (itr.hasNext()) {
				FileItem item = (FileItem) itr.next();
				//Handle Form Fields.
				if(item.isFormField()) {
					parameterMap.put(item.getFieldName(), item.getString());
					System.out.println(item.getFieldName() + "/" + item.getString());
					Debug.log(this, "loadParameterWithMultipart", item.getFieldName() + "/" + item.getString());
				}
				else {
					parameterMap.put(item.getFieldName(), item.getName());
					//upload file
					Debug.log(this, "loadParameterWithMultipart", item.getFieldName() + "/" + item.getName());
					File file = new File(destinationDir,item.getName());
					item.write(file);
					Debug.log("File uploaded: " + getServletContext().getRealPath("/images/plats") + "\\" + item.getName());
				}
			}
			List<FileItem> items1 = uploader.parseRequest(request);			
			Debug.log(this, "loadParameterWithMultipart", items1.toString());
		}
		catch (FileUploadException ex) {
			ex.printStackTrace();
		}
		catch (Exception ex) {
			ex.printStackTrace();
		}
	}	
	
	@Override
	public void init(ServletConfig config) throws ServletException {
		super.init(config);
		String realPath = getServletContext().getRealPath(DESTINATION_DIR_PATH);
		destinationDir = new File(realPath);
		if (!destinationDir.isDirectory()) {
			throw new ServletException(DESTINATION_DIR_PATH + " is not a directory");
		}
	}
	
	//upload
	private static final String DESTINATION_DIR_PATH ="/images/plats";
	private File destinationDir;
}
